package config

import (
	_ "embed"
	"fmt"
	"os"
	"path/filepath"
	"runtime"

	"gopkg.in/yaml.v3"
)

// Config 全局配置
type Config struct {
	Server `yaml:"server" json:"server"`
	Mysql  `yaml:"mysql" json:"mysql"`
	Log    `yaml:"log" json:"log"`
	JWT    `yaml:"jwt" json:"jwt"`
}

//go:embed default.yaml
var defaultConfig []byte

func NewConfig(configFile string) *Config {
	// 读取默认配置
	var instance = &Config{}
	err := yaml.Unmarshal(defaultConfig, instance)
	if err != nil {
		panic(fmt.Sprintf("default yaml Unmarshal err: %v", err))
	}

	// 将用户配置覆盖掉默认配置
	fmt.Println("config file:", configFile)
	dataBytes, err := os.ReadFile(configFile)
	if err != nil {
		panic(fmt.Sprintf("read config file failed: %v", err))
	}

	err = yaml.Unmarshal(dataBytes, instance)
	if err != nil {
		panic(fmt.Sprintf("parse config file err: %s\n", err))
	}

	return instance
}

// Server web应用配置
type Server struct {
	Mode string `yaml:"mode" json:"mode"`
	Port int    `yaml:"port" json:"port"`
}

// Mysql 配置
type Mysql struct {
	Host     string `yaml:"host" json:"host"`
	Port     int    `yaml:"port" json:"port"`
	User     string `yaml:"user" json:"user"`
	Password string `yaml:"password" json:"password"`
	Database string `yaml:"database" json:"database"`
}

func (m Mysql) ConnStr() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%v)/%s?charset=utf8", m.User, m.Password, m.Host, m.Port, m.Database)
}

// Log 配置
type Log struct {
	Level string `yaml:"level" json:"level"`
	Path  string `yaml:"path" json:"path"`
}

// JWT 配置
type JWT struct {
	SignKey    string `yaml:"signKey" json:"signKey"`
	ExpireTime string `yaml:"expireTime" json:"expireTime"` // time.ParseDuration
}

func getRootPath() (string, error) {
	_, file, _, ok := runtime.Caller(0)
	if !ok {
		return "", fmt.Errorf("failed to get root path")
	}
	dir := filepath.Dir(filepath.Dir(file))
	return dir, nil
}

func getCurrentExecutableDir() (string, error) {
	exePath, err := os.Executable()
	if err != nil {
		return "", fmt.Errorf("failed to get executable path: %w", err)
	}
	dir := filepath.Dir(exePath)
	return dir, nil
}
